// // call方法的使用

// window.name = '李四'
// function test(a, b) {
//   console.log(this.name, a, b)
// }
// const obj = {
//   name: '张三'
// }
// test.call(obj, '1', '2')
// test('1', '2')


// apply方法的使用


// function test(...arg) {
//   console.log(this.name, ...arg) // 张三 1 2
// }
// const obj = {
//   name: '张三'
// }
// test.apply(obj, ['1', '2']) 


// bind方法的使用

// 1、返回的函数作为普通函数使用

// function test(a, b, c) {
//   console.log(this.name, a, b, c) // 张三 1 2
// }
// const obj = {
//   name: '张三'
// }
// test.bind(obj, '1', '2')('3')


// // 2、返回的函数作为普通函数使用
// function test1(a, b, c, name) {
//   this.name = name
//   console.log(this.name, a, b, c) // 张三 1 2
// }
// const obj1 = {
//   name: '张三'
// }
// const S = test1.bind(obj1, '1', '2', '3')

// const s = new S('王五')


// 封装call方法

// window.name = '李四'
// Function.prototype.myCall = function (obj, ...arg) {
//   obj = obj || window
//   key = Symbol('key') // 避免与obj的属性相同，将其覆盖
//   obj[key] = this // 拿到调用的函数，并赋值给obj
//   obj[key](...arg)
//   delete obj[key] // 运行完删除属性，避免obj无故新增属性
// }

// function test(a, b) {
//   console.log(this.name, a, b)
// }
// const obj = {
//   name: '张三'
// }
// test.myCall(obj, '1', '2') // 张三 1 2
// test('1', '2') // 李四 1 2



// Function.prototype.myApply = function (obj, arg) {
//   obj = obj || window
//   key = Symbol('key') // 避免与obj的属性相同，将其覆盖
//   obj[key] = this // 拿到调用的函数，并赋值给obj
//   obj[key](...arg)
//   delete obj[key] // 运行完删除属性，避免obj无故新增属性
// }

// function test(a, b) {
//   console.log(this.name, a, b)
// }
// const obj = {
//   name: '张三'
// }
// test.myApply(obj, ['1', '2']) // 张三 1 2


// 封装bind方法

Function.prototype.myBind = function (obj, ...arg) {
  obj = obj || window
  let key = Symbol('key')
  obj[key] = this
  const _this = this
  return function (...Arg) {
    let arr = [...arg, ...Arg]
    if(this instanceof _this) { // 重点：这里是判断
      let newKey = Symbol('newKey')
      this[newKey] = _this
      this[newKey](...arr)
      delete this[newKey]
    }else {
      obj[key](...arr)
      delete obj[key]
    }
  }
}

// 1、返回的函数作为普通函数使用
function test(a, b, c) {
  console.log(this.name, a, b, c) // 张三 1 2
}
const obj = {
  name: '张三'
}
test.myBind(obj, '1', '2')('3')


// 2、返回的函数作为普通函数使用
function test1(a, b, c, name) {
  this.name = name
  console.log(this.name, a, b, c) // 张三 1 2
}
const obj1 = {
  name: '张三'
}
const S = test1.myBind(obj1, '1', '2', '3')

const s = new S('王五')
